package com.tduck.cloud.poster.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.freewayso.image.combiner.ImageCombiner;
import com.freewayso.image.combiner.element.CombineElement;
import com.freewayso.image.combiner.element.ImageElement;
import com.freewayso.image.combiner.element.TextElement;
import com.freewayso.image.combiner.enums.ZoomMode;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.tduck.cloud.poster.entity.PosterEntity;
import com.tduck.cloud.poster.entity.widget.ImageWidget;
import com.tduck.cloud.poster.entity.widget.PosterWidget;
import com.tduck.cloud.poster.entity.widget.QrcodeWidget;
import com.tduck.cloud.poster.entity.widget.TextWidget;
import com.tduck.cloud.storage.cloud.OssStorageFactory;
import lombok.Data;
import lombok.experimental.UtilityClass;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.Map;

/**
 * @author : tduck
 * @description :  图片合成工具类
 * @create :  2023/02/01 11:34
 **/
@Data
@UtilityClass
public class ImageCombinerBuilder {


    /**
     * 根据海报设计对象合成图片
     */
    public static ImageCombiner build(PosterEntity poster) throws Exception {
        if (null == poster) {
            return null;
        }
        PosterEntity.PosterConfig posterConfig = poster.getPosterConfig();
        ImageCombiner imageCombiner = buildCanvas(posterConfig);
        // 添加组件
        poster.getPosterWidgetList().forEach(posterWidget -> {
            try {
                imageCombiner.addElement(buildElement(posterWidget));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        //执行图片合并
        imageCombiner.combine();
        return imageCombiner;
    }


    /**
     * 根据海报设计对象合成图片
     *
     * @param data 数据
     * @return 图片合成器
     */
    public static ImageCombiner build(PosterEntity poster, Map<String, String> data) throws Exception {
        if (null == poster) {
            return null;
        }
        PosterEntity.PosterConfig posterConfig = poster.getPosterConfig();
        ImageCombiner imageCombiner = buildCanvas(posterConfig);
        // 添加组件
        poster.getPosterWidgetList().forEach(posterWidget -> {
            try {
                // 文字组件动态替换 文字
                if (StrUtil.equals(MapUtil.getStr(posterWidget, PosterWidget.Fields.type),
                        PosterWidget.PosterWidgetType.TEXT.toString())) {
                    posterWidget.put(TextWidget.Fields.text, data.get(MapUtil.getStr(posterWidget, PosterWidget.Fields.id)));
                }
                imageCombiner.addElement(buildElement(posterWidget));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        //执行图片合并
        imageCombiner.combine();
        return imageCombiner;
    }


    /**
     * 上传图片获取连接
     */
    public static String uploadImageUrl(String posterKey, InputStream inputStream) throws Exception {
        String filePath = StrUtil.format("poster/{}/{}.png", posterKey, IdUtil.simpleUUID());
        return OssStorageFactory.getStorageService().upload(inputStream, filePath);
    }


    /**
     * 构建海报组件
     *
     * @param posterWidgetMap 组件
     * @return 组件
     */
    public static CombineElement buildElement(Map<String, Object> posterWidgetMap) throws Exception {
        PosterWidget posterWidget = BeanUtil.toBeanIgnoreError(posterWidgetMap, PosterWidget.class);
        switch (posterWidget.getType()) {
            case TEXT:
                return buildTextElement(posterWidgetMap);
            case IMAGE:
                return buildImageElement(posterWidgetMap);
            case QRCODE:
                return buildQrcodeElement(posterWidgetMap);
            default:
                throw new RuntimeException("未知组件类型");
        }
    }

    private static ImageElement buildQrcodeElement(Map<String, Object> posterWidgetMap) {
        QrcodeWidget qrcodeWidget = BeanUtil.toBeanIgnoreError(posterWidgetMap, QrcodeWidget.class);
        // 生成二维码
        QrConfig config = new QrConfig(qrcodeWidget.getWidth(), qrcodeWidget.getWidth());
        config.setBackColor(ImgUtil.hexToColor(qrcodeWidget.getBgColor()));
        config.setForeColor(ImgUtil.hexToColor(qrcodeWidget.getFgColor()));
        config.setMargin(qrcodeWidget.getMargin());
        config.setErrorCorrection(ErrorCorrectionLevel.H);
        BufferedImage qrCodeImage = QrCodeUtil.generate(qrcodeWidget.getUrl(), config);
        return new ImageElement(qrCodeImage, qrcodeWidget.getX(), qrcodeWidget.getY(), qrcodeWidget.getWidth(), qrcodeWidget.getHeight(), ZoomMode.WidthHeight);
    }

    /**
     * 图片组件构建
     *
     * @param posterWidgetMap 组件
     * @return 组件
     */
    private static ImageElement buildImageElement(Map<String, Object> posterWidgetMap) throws Exception {
        ImageWidget imageWidget = BeanUtil.toBeanIgnoreError(posterWidgetMap, ImageWidget.class);
        // 是否是url
        ImageElement imageElement = null;
        if (Validator.isUrl(imageWidget.getImgUrl())) {
            imageElement = new ImageElement(imageWidget.getImgUrl(), imageWidget.getX(), imageWidget.getY(), imageWidget.getWidth(), imageWidget.getHeight(), imageWidget.getZoomMode());
        } else {
            // base64的图片转BufferedImage 需要先移除base64头 ...
            String imgUrl = imageWidget.getImgUrl();
            byte[] bytes = Base64.decode(StrUtil.subAfter(imgUrl, ",", false));
            BufferedImage bufferedImage = ImgUtil.toImage(bytes);
            imageElement = new ImageElement(bufferedImage, imageWidget.getX(), imageWidget.getY(), imageWidget.getWidth(), imageWidget.getHeight(), imageWidget.getZoomMode());
        }
        imageElement.setWidth(imageWidget.getWidth());
        imageElement.setHeight(imageWidget.getHeight());
        imageElement.setRotate(imageWidget.getRotate());
        imageElement.setBlur(imageWidget.getBlur());
        imageElement.setRoundCorner(imageWidget.getRoundCorner());
        return imageElement;
    }


    /**
     * 文件组件构建
     *
     * @param posterWidgetMap 组件
     * @return 组件
     */
    private static TextElement buildTextElement(Map<String, Object> posterWidgetMap) {
        TextWidget textWidget = BeanUtil.toBeanIgnoreError(posterWidgetMap, TextWidget.class);
        // 处理字体
        Font font = FontUtils.getFont(textWidget.getFontName());
        font = font.deriveFont(Font.PLAIN, textWidget.getFontSize());
        TextElement textElement = new TextElement(textWidget.getText(), font, textWidget.getX(), textWidget.getY());
        Color color = ImgUtil.hexToColor(textWidget.getColor());
        textElement.setColor(color);
        textElement.setRotate(textWidget.getRotate());
        textElement.setLineHeight(textWidget.getLineHeight());
        textElement.setStrikeThrough(textWidget.isStrikeThrough());
        textElement.setSpace(textWidget.getSpace());
        textElement.setCenter(textWidget.isCenter());
        return textElement;
    }


    /**
     * 构建海报画布
     *
     * @param posterConfig 海报配置
     */
    private static ImageCombiner buildCanvas(PosterEntity.PosterConfig posterConfig) throws Exception {
        ImageCombiner imageCombiner = imageCombiner = new ImageCombiner(posterConfig.getWidth(), posterConfig.getHeight(), posterConfig.getPosterFileType());
        // 如果有背景图，则使用背景图作为画布
        if (StrUtil.isNotBlank(posterConfig.getPosterBgImage())) {
            imageCombiner = new ImageCombiner(posterConfig.getPosterBgImage(), posterConfig.getWidth(), posterConfig.getHeight(), ZoomMode.WidthHeight, posterConfig.getPosterFileType());
        } else if (StrUtil.isNotBlank(posterConfig.getPosterBgColor())) {
            // 如果有背景色，则使用背景色作为画布
            Color color = ImgUtil.hexToColor(posterConfig.getPosterBgColor());
            imageCombiner = new ImageCombiner(posterConfig.getWidth(), posterConfig.getHeight(), color, posterConfig.getPosterFileType());
        }
        return imageCombiner;
    }


}
